﻿namespace TestTool.GUI.Controllers
{
    using System;
    using System.Globalization;
    using System.Threading;
    using System.Xml;
    using TestTool.GUI.Data;
    using TestTool.GUI.Enums;
    using TestTool.GUI.Utils;
    using TestTool.GUI.Views;
    using TestTool.Proxies.Onvif;
    using TestTool.Tests.Common.CommonUtils;

    internal class PtzController : Controller<IPtzView>
    {
        private ManagementServiceProvider _deviceClient;
        private bool _deviceClientWorking;
        private MediaServiceProvider _mediaClient;
        private bool _mediaClientWorking;
        private TestTool.Proxies.Onvif.Profile _profile;
        private PTZServiceProvider _ptzClient;
        private bool _ptzClientWorking;

        public PtzController(IPtzView view) : base(view)
        {
        }

        public void AbosuteRelativeIncrementalMove(bool absolute, string profile, decimal xmin, decimal xmax, decimal ymin, decimal ymax, decimal zmin, decimal zmax)
        {
            this._ptzClientWorking = true;
            this.IntializePtzClient(base.View.PTZAddress);
            this._ptzClient.AbosuteRelativeIncrementalMove(absolute, profile, xmin, xmax, ymin, ymax, zmin, zmax);
        }

        public void AbosuteRelativeMove(bool absolute, string profile, decimal x, decimal y, decimal z)
        {
            this._ptzClientWorking = true;
            this.IntializePtzClient(base.View.PTZAddress);
            PTZVector position = new PTZVector {
                PanTilt = new Vector2D()
            };
            position.PanTilt.space = absolute ? "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace" : "http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace";
            position.PanTilt.x = (float) x;
            position.PanTilt.y = (float) y;
            position.Zoom = new Vector1D();
            position.Zoom.space = absolute ? "http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace" : "http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace";
            position.Zoom.x = (float) z;
            if (absolute)
            {
                this._ptzClient.AbsoluteMove(profile, position);
            }
            else
            {
                this._ptzClient.RelativeMove(profile, position);
            }
        }

        public void AddPTZConfiguration(TestTool.Proxies.Onvif.Profile profile)
        {
            this._ptzClientWorking = true;
            this.IntializePtzClient(base.View.PTZAddress);
            this._profile = profile;
            this._ptzClient.GetConfigurations();
        }

        public void ContinuousMove(string profile, bool panTilt, bool zoom, decimal x, decimal y, decimal z, int timeout)
        {
            this._ptzClientWorking = true;
            this.IntializePtzClient(base.View.PTZAddress);
            PTZSpeed speed = new PTZSpeed();
            if (panTilt)
            {
                speed.PanTilt = new Vector2D();
                speed.PanTilt.space = "http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace";
                speed.PanTilt.x = (float) x;
                speed.PanTilt.y = (float) y;
            }
            if (zoom)
            {
                speed.Zoom = new Vector1D();
                speed.Zoom.space = "http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace";
                speed.Zoom.x = (float) z;
            }
            string str = null;
            if (timeout > 0)
            {
                str = XmlConvert.ToString(TimeSpan.FromMilliseconds((double) timeout));
            }
            this._ptzClient.ContinuousMove(profile, speed, str);
        }

        public void GetAddress(CapabilityCategory[] categories)
        {
            DiscoveredDevices discoveredDevices = ContextController.GetDiscoveredDevices();
            this._deviceClientWorking = true;
            string address = (discoveredDevices != null) ? discoveredDevices.ServiceAddress : string.Empty;
            this.InitializeDeviceClient(address);
            bool capabilitiesStyle = ContextController.GetDebugInfo().CapabilitiesExchange == CapabilitiesExchangeStyle.GetCapabilities;
            this._deviceClient.GetServiceAddresses(capabilitiesStyle, categories);
        }

        public void GetProfiles()
        {
            this._mediaClientWorking = true;
            this.InitializeMediaClient(base.View.MediaAddress);
            this._mediaClient.GetProfiles();
        }

        public void GetStreamUri()
        {
            this._mediaClientWorking = true;
            this.InitializeMediaClient(base.View.MediaAddress);
            this._mediaClient.GetMediaUri();
        }

        private void InitializeDeviceClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._deviceClient = new ManagementServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._deviceClient.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._deviceClient.OperationCompleted += new Action(this.OnOperationCompleted);
            this._deviceClient.OperationStarted += new Action(this.OnOperationStarted);
            this._deviceClient.Timeout = deviceEnvironment.Timeouts.Message;
            this._deviceClient.ResponseReceived += new Action<string>(this.OnResponseReceived);
            this._deviceClient.OnServicesInfoReceived += new ManagementServiceProvider.ServicesInfoReceived(this.OnServicesInfoReceived);
            this._deviceClient.Security = ContextController.GetDebugInfo().Security;
        }

        private void InitializeMediaClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._mediaClient = new MediaServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._mediaClient.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._mediaClient.OperationCompleted += new Action(this.OnOperationCompleted);
            this._mediaClient.OperationStarted += new Action(this.OnOperationStarted);
            this._mediaClient.OnMediaUriReceived += new MediaServiceProvider.MediaUriReceived(this.OnMediaUriReceived);
            this._mediaClient.Timeout = deviceEnvironment.Timeouts.Message;
            this._mediaClient.ResponseReceived += new Action<string>(this.OnResponseReceived);
            this._mediaClient.OnProfilesReceived += new MediaServiceProvider.ProfilesReceived(this.OnProfilesReceived);
            this._mediaClient.OnPTZConfigurationAdded += new MediaServiceProvider.PTZConfigurationAdded(this.OnPTZConfigurationAdded);
            this._mediaClient.Security = ContextController.GetDebugInfo().Security;
        }

        private void IntializePtzClient(string address)
        {
            DeviceEnvironment deviceEnvironment = ContextController.GetDeviceEnvironment();
            this._ptzClient = new PTZServiceProvider(address, deviceEnvironment.Timeouts.Message);
            this._ptzClient.ExceptionThrown += new Action<string, Exception>(this.OnExceptionThrown);
            this._ptzClient.OperationCompleted += new Action(this.OnOperationCompleted);
            this._ptzClient.OperationStarted += new Action(this.OnOperationStarted);
            this._ptzClient.Timeout = deviceEnvironment.Timeouts.Message;
            this._ptzClient.ResponseReceived += new Action<string>(this.OnResponseReceived);
            this._ptzClient.OnPTZConfigurationsReceived += new PTZServiceProvider.PTZConfigurationReceived(this.OnPTZConfigurationsReceived);
            this._ptzClient.Security = ContextController.GetDebugInfo().Security;
        }

        public override void LoadSavedContext(SavedContext context)
        {
            if (context.PTZInfo != null)
            {
                base.View.PTZAddress = context.PTZInfo.ServiceAddress;
                base.View.MediaAddress = context.PTZInfo.MediaAddress;
            }
        }

        private void OnExceptionThrown(string stage, Exception exc)
        {
            string message;
            if (this._mediaClientWorking)
            {
                this._mediaClientWorking = false;
            }
            if (this._deviceClientWorking)
            {
                this._deviceClientWorking = false;
            }
            if (this._ptzClientWorking)
            {
                this._ptzClientWorking = false;
            }
            base.ReportOperationCompleted();
            this.SwitchToState(TestTool.GUI.Enums.ApplicationState.Idle);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            if (!string.IsNullOrEmpty(stage))
            {
                message = string.Format("{0}{1}{2}", stage, Environment.NewLine, exc.Message);
            }
            else
            {
                message = exc.Message;
            }
            base.View.DisplayLog(message.Replace("\n", Environment.NewLine));
        }

        protected void OnMediaUriReceived(MediaUri uri, VideoEncoderConfiguration encoder, AudioEncoderConfiguration audio)
        {
            base.View.ShowVideo(uri, encoder);
        }

        private void OnOperationCompleted()
        {
            if (this._mediaClientWorking)
            {
                this._mediaClientWorking = false;
            }
            if (this._deviceClientWorking)
            {
                this._deviceClientWorking = false;
            }
            if (this._ptzClientWorking)
            {
                this._ptzClientWorking = false;
            }
            base.ReportOperationCompleted();
        }

        private void OnOperationStarted()
        {
            base.ReportOperationStarted();
        }

        protected void OnProfilesReceived(TestTool.Proxies.Onvif.Profile[] profiles)
        {
            base.View.SetProfiles(profiles);
        }

        protected void OnPTZConfigurationAdded(string profile, string configuration)
        {
            base.View.OnPTZConfigurationAdded(profile, configuration);
        }

        protected void OnPTZConfigurationsReceived(PTZConfiguration[] configs)
        {
            if ((configs == null) || (configs.Length == 0))
            {
                throw new Exception("No PTZ configuration available");
            }
            this._mediaClientWorking = true;
            this.InitializeMediaClient(base.View.MediaAddress);
            this._mediaClient.AddPTZConfiguration(this._profile.token, configs[0].token);
        }

        private void OnResponseReceived(string response)
        {
            base.View.DisplayLog(response);
        }

        private void OnServicesInfoReceived(Capabilities capabilities, Service[] services)
        {
            base.View.PTZAddress = string.Empty;
            base.View.MediaAddress = string.Empty;
            if (capabilities != null)
            {
                if (capabilities.PTZ != null)
                {
                    base.View.PTZAddress = capabilities.PTZ.XAddr;
                }
                if (capabilities.Media != null)
                {
                    base.View.MediaAddress = capabilities.Media.XAddr;
                }
            }
            else if (services != null)
            {
                Service service = services.FindService("http://www.onvif.org/ver10/media/wsdl");
                if (service != null)
                {
                    base.View.MediaAddress = service.XAddr;
                }
                Service service2 = services.FindService("http://www.onvif.org/ver20/ptz/wsdl");
                if (service2 != null)
                {
                    base.View.PTZAddress = service2.XAddr;
                }
            }
        }

        public override void Stop()
        {
            if (this._deviceClientWorking)
            {
                this._deviceClient.Stop();
            }
            if (this._mediaClientWorking)
            {
                this._mediaClient.Stop();
            }
            if (this._ptzClientWorking)
            {
                this._ptzClient.Stop();
            }
        }

        public void Stop(string profile, bool panTilt, bool zoom)
        {
            this._ptzClientWorking = true;
            this.IntializePtzClient(base.View.PTZAddress);
            this._ptzClient.Stop(profile, panTilt, zoom);
        }

        public override void UpdateContext()
        {
            PTZInfo info = new PTZInfo {
                ServiceAddress = base.View.PTZAddress,
                MediaAddress = base.View.MediaAddress
            };
            ContextController.UpdatePTZInfo(info);
        }

        public override void UpdateView()
        {
            base.View.EnableControls(base.CurrentState == TestTool.GUI.Enums.ApplicationState.Idle);
        }

        public override bool RequestPending
        {
            get
            {
                if (!this._deviceClientWorking && !this._mediaClientWorking)
                {
                    return this._ptzClientWorking;
                }
                return true;
            }
        }
    }
}

